package request

import (
	"context"
	"fmt"
	"github.com/gogf/gf/v2/encoding/gjson"
	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/net/gclient"
	"github.com/gogf/gf/v2/os/gctx"
	"learn-goframe/internal/model/request"
	"learn-goframe/internal/service"
	"strings"
	"time"
)

type sRequest struct{}

func init() {
	service.RegisterRequest(newRequest())
}

func newRequest() *sRequest {
	return &sRequest{}
}

var cfgSSO, _ = g.Cfg().Get(gctx.New(), "sso")
var cfgGeoChat, _ = g.Cfg().Get(gctx.New(), "geoChat")

// DecodeFunc 是一个泛型解码函数接口，用于处理不同的响应体类型。
type DecodeFunc[T any] func(response *gclient.Response) (T, error)

// baseSendRequest 是一个独立的通用发送请求函数，使用泛型处理响应体。
func baseSendRequest[T any](ctx context.Context, client *gclient.Client, in request.Params, decode DecodeFunc[T], maxRetries int) (out T, err error) {
	r, err := client.DoRequest(ctx, in.Method, in.URL, in.Data)
	g.Log().Debug(ctx, "baseSendRequest args:", in)

	if err != nil {
		return out, err
	}
	defer func(r *gclient.Response) {
		err := r.Close()
		if err != nil {
			g.Log().Error(ctx, err)
			panic(err)
		}
	}(r)

	out, err = decode(r)
	if err != nil {
		if maxRetries > 0 && strings.ToLower(in.Method) == "get" {
			g.Log().Debug(ctx, "retry send request ...")

			time.Sleep(2 * time.Second)
			return baseSendRequest[T](ctx, client, in, decode, maxRetries-1)
		}

		return out, err
	}

	return out, nil
}

// decodeJSON 是一个解码函数，将响应体解析为 gjson.Json。
func decodeJSON(response *gclient.Response) (*gjson.Json, error) {
	return gjson.DecodeToJson(response.ReadAll())
}

// decodeString 是一个解码函数，将响应体作为字符串返回。
func decodeString(response *gclient.Response) (*string, error) {
	body := response.ReadAllString()
	return &body, nil
}

// sRequest的方法中调用baseSendRequest来处理泛型
func (s *sRequest) sendRequestJSON(ctx context.Context, in request.Params) (*gjson.Json, error) {
	client := g.Client().Header(in.Headers)
	return baseSendRequest(ctx, client, in, decodeJSON, 10)
}

func (s *sRequest) sendRequestString(ctx context.Context, in request.Params) (*string, error) {
	client := g.Client().Header(in.Headers)
	return baseSendRequest(ctx, client, in, decodeString, 10)
}

// SendSSORequest 发送SSO请求
func (s *sRequest) SendSSORequest(ctx context.Context, in request.Params) (out *gjson.Json, err error) {
	cfgObj := cfgSSO.MapStrStr()

	in.Headers = make(map[string]string, 1)

	if service.BizCtx().Get(ctx) != nil {
		in.Headers["Authorization"] = fmt.Sprintf("Bearer %s", service.BizCtx().Get(ctx).User.Token)
	}

	in.URL = fmt.Sprintf("%s%s", cfgObj["apiHost"], in.URL)

	out, err = s.sendRequestJSON(ctx, in)
	if err != nil {
		return nil, err
	}

	if out.Get("statusCode").Int() != 0 {
		return nil, gerror.Newf("sso error: %s", out.Get("message"))
	}

	return out, nil
}
